home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_065 / prep / misc.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  20KB  |  829 lines

  1. /* misc routines */
  2.  
  3. #include "prep.h"
  4.  
  5.  
  6.  
  7.  
  8. /* Function DUMP.C
  9.  *
  10.  *   Send a string to the output stream.  The string is a
  11.  * fortran record constructed by PREP, which may be
  12.  * longer than 72 characters after processing.  It is
  13.  * broken up into pieces before output.  The string
  14.  * must be null terminated.  The string is not affected
  15.  * by this routine, so it is safe to do
  16.  *       dump( "explicit text" ) ;
  17.  *
  18.  *   If inside a vector loop (vec_flag==TRUE) the record is
  19.  * not broken up and is sent to mem_store rather than a file.
  20.  *
  21.  * P. R. OVE  11/9/85
  22.  */
  23.  
  24. dump( string ) 
  25. char     *string ;
  26.  
  27. {
  28. char    record[73], *pntr ;
  29. int    i_str, i_rec = 0, i, i_tab, quote_flag = 0 ;
  30.  
  31. /* ignore empty lines sent here */
  32. if ( NULL == line_end( string ) ) return ;
  33.  
  34. /* if in a vector loop write the string to mem_store */
  35. if ( vec_flag ) {
  36.     push( string ) ;
  37.     return ;
  38. }
  39.  
  40. /* loop until end of record */
  41. for ( i_str = 0;; i_str++ ) {
  42.  
  43.     /* wrap up on end of line */
  44.     if ( line_end( &string[i_str] ) == NULL ) {
  45.                record[i_rec] = NULL ;
  46.         put_string( record ) ;
  47.         break ; }
  48.  
  49.     /* break string if necessary */
  50.     if ( i_rec >= 72 ) {                
  51.         record[i_rec] = NULL ;
  52.         put_string( record ) ;
  53.         strcpy( record, "     *" ) ;
  54.         i_str-- ;
  55.         i_rec = 6 ;
  56.         continue ;
  57.     }
  58.  
  59.     /* toggle quote flag on quotes */
  60.     if ( string[i_str] == '\'' ) quote_flag = ! quote_flag ;
  61.         
  62.     /* underline filtering */
  63.     if ( (string[i_str]=='_') && (!underline_keep) && (!quote_flag) )
  64.         continue ;
  65.  
  66.     /* tab handling */
  67.     if ( string[i_str] == TAB ) {
  68.         if (    i_rec >= 70 - tab_size ) {
  69.             record[i_rec] = NULL ;
  70.             put_string( record ) ;
  71.             strcpy( record, "     *" ) ;
  72.             i_rec = 6 ; }
  73.  
  74.         else {  /* replace tab by blanks */
  75.             i_tab = ( ( i_rec + 1 )/tab_size ) 
  76.                   * tab_size - i_rec + tab_size - 1 ;
  77.             for ( i = 0; i < i_tab; i++ ) {
  78.                 record[i_rec] = BLANK ;
  79.                         i_rec++ ; }
  80.         }
  81.         continue ;
  82.     }
  83.  
  84.             
  85.     /* default action */
  86.     record[i_rec] = string[i_str] ;
  87.     i_rec++ ;
  88.  
  89. }                       
  90. }                          
  91.  
  92.  
  93.  
  94.  
  95. /* GET_RECORD
  96.  *
  97.  * Get a record from the input stream, making sure that the buffer
  98.  * does not overflow by increasing its size as necessary.  The 
  99.  * string in_buff will contain the record on return.  In_buff will
  100.  * always contain about ten percent of its default length in trailing 
  101.  * blanks to play with.  Out_buff will have space allocated for it
  102.  * as well, 4 times that of in_buff.  Returns a pointer to the 
  103.  * terminating NULL character.  On EOF the previous input file
  104.  * (assuming the present one was an include file) will be restored as
  105.  * the input file.  If the filestack is empty return NULL.
  106.  */
  107.  
  108. char    *get_rec()
  109. {
  110. int    i, j ;
  111. char    *pntr, *area ;
  112.  
  113. /* fill the in_put buffer, enlarging it when nearly full in 
  114.  * increments of DEF_BUFFSIZE.  On end of file the previous file
  115.  * handle is popped from the include stack (if present).
  116.  */
  117. pntr = in_buff ;
  118. i = 0 ;
  119. while(1) {
  120.  
  121.     for (; i < allocation - DEF_BUFFSIZE/10 ; i++, pntr++ ) {
  122.         *pntr = getc(in) ;
  123.         if ( *pntr == EOF || *pntr == 0x1A ) {
  124.             fclose(in) ;
  125.             if ( NULL == popfile(&in) ) return( NULL ) ;
  126.             pntr = in_buff-1 ;
  127.             i = -1 ;
  128.             continue ;
  129.         }
  130.         if ( *pntr == '\n' ) {
  131.             *pntr = NULL ;
  132.             return( pntr ) ;
  133.         }
  134.     }
  135.  
  136.  
  137.     /* if control falls through to here, increase buffer sizes. */
  138.     allocation += DEF_BUFFSIZE ;
  139.     if ( NULL == ( in_buff = realloc( in_buff, allocation ) ) )
  140.         abort( "Reallocation failed" ) ;
  141.     if ( NULL == ( out_buff = realloc( out_buff, 4*allocation ) ) )
  142.         abort( "Reallocation failed" ) ;
  143. }
  144.  
  145. }
  146.  
  147.  
  148.  
  149. /* Function LINE_END
  150.  *
  151.  * Return a NULL pointer if the string contains only
  152.  * blanks and tabs or if it is a NULL string.  Else
  153.  * return a pointer to the first offending character.
  154.  *
  155.  * P. R. OVE  11/9/85
  156.  */
  157.  
  158. char    *line_end( string ) 
  159. char     *string ;
  160.  
  161. {
  162.     for (; *string != NULL; string++ )
  163.         if ( (*string != BLANK) && (*string != TAB) ) return(string) ;
  164.  
  165.     return( NULL ) ;
  166. }
  167.  
  168.  
  169.  
  170.  
  171. /* Function MAT_DEL
  172.  *
  173.  * Given pointer to a delimeter this routine finds its
  174.  * partner and returns a pointer to it.  On failure a
  175.  * NULL pointer is returned.  The supported delimeters
  176.  * are:
  177.  *
  178.  *   '  "  ( )  [ ]  { }  < >
  179.  *
  180.  * ' and " are supported only in the forward direction
  181.  * and no nesting is detected.
  182.  * In all cases the search is limited to the current
  183.  * line (bounded by NULLs).
  184.  *
  185.  * P. R. OVE  11/9/85
  186.  */
  187.  
  188.  
  189. char *mat_del( pntr )
  190. char    *pntr ;
  191.  
  192. {
  193. int    nest_count = 0, i, direction ;
  194. char    target ;
  195.  
  196. if ( pntr == NULL ) return( NULL ) ;
  197.  
  198. /* get the target character and direction of search */
  199.     switch( *pntr ) {
  200.  
  201.         case '(' :    { target = ')' ;
  202.                   direction = 1 ;
  203.                   break ;          }
  204.  
  205.         case ')' :    { target = '(' ;
  206.                   direction = -1 ;
  207.                   break ;          }
  208.  
  209.         case '[' :    { target = ']' ;
  210.                   direction = 1 ;
  211.                   break ;          }
  212.  
  213.         case ']' :    { target = '[' ;
  214.                   direction = -1 ;
  215.                   break ;          }
  216.  
  217.         case '{' :    { target = '}' ;
  218.                   direction = 1 ;
  219.                   break ;          }
  220.  
  221.         case '}' :    { target = '{' ;
  222.                   direction = -1 ;
  223.                   break ;          }
  224.  
  225.         case '<' :    { target = '>' ;
  226.                   direction = 1 ;
  227.                   break ;          }
  228.  
  229.         case '>' :    { target = '<' ;
  230.                   direction = -1 ;
  231.                   break ;          }
  232.  
  233.         case '\'':    { target = '\'' ;
  234.                   direction = 1 ;
  235.                   break ;          }
  236.  
  237.         case '\"':    { target = '\"' ;
  238.                   direction = 1 ;
  239.                   break ;          }
  240.  
  241.         default:      return( NULL ) ;
  242.                 
  243.     }
  244.  
  245. /* find the match */
  246.     for ( i = direction; pntr[i] != NULL; i += direction ) {
  247.         
  248.         if ( pntr[i] == target ) {
  249.  
  250.             if ( nest_count == 0 ) {
  251.                 break ;    }
  252.             else {
  253.                 nest_count-- ;
  254.                 continue ; }
  255.                 }
  256.         
  257.         if ( pntr[i] == pntr[0] ) nest_count++ ;
  258.     }
  259.  
  260.     if ( &pntr[i] == NULL ) return( NULL ) ;
  261.     return( &pntr[i] ) ;
  262. }
  263.  
  264.  
  265.  
  266.  
  267. /* PARMER
  268.  *
  269.  * Processes the command line parameters.
  270.  */
  271.  
  272. int parmer ( argc, argv )
  273. int    argc ;
  274. char    *argv[] ;
  275. {
  276. int    i ;
  277.     
  278. /* default io streams */
  279. in = stdin ;
  280. out = stdout ;
  281.  
  282. /* use in_buff to hold file inclusion command if found (1 only) */
  283. IN_BUFF_DONE ;         /* clear the buffer */
  284.  
  285.  
  286. for ( i = 1; i < argc; i++ ) {
  287.  
  288.     /* assume data file name if not a switch */
  289.     if ( argv[i][0] != '-' ) {
  290.         sprintf( dataf, "%s.p", argv[i] ) ;
  291.         if ( NULL != ( in = fopen( dataf, "r" ) ) ) {
  292.             sprintf( dataf, "%s.f", argv[i] ) ;
  293.             out = fopen( dataf, "w" ) ;
  294.         }
  295.         else in = stdin ;
  296.     }
  297.     
  298.     else {
  299.     /* switches */
  300.         switch ( argv[i][1] ) {
  301.  
  302.         case 'c' : case 'C' :
  303.             com_keep = TRUE ;    break ;
  304.  
  305.         case 'u' : case 'U' :
  306.             underline_keep = TRUE ;    break ;
  307.  
  308.         case 'r' : case 'R' :
  309.             i++ ;
  310.             if ( i < argc ) {
  311.             if ( argv[i][0] == '-' ||
  312.                 NULL == sscanf(argv[i],"%d",&unroll_depth)) {
  313.                 unroll_depth = DEF_UNROLL_DEPTH ;
  314.                 i-- ;
  315.                 break ;
  316.             }}
  317.             else    unroll_depth = DEF_UNROLL_DEPTH ;
  318.             break ;
  319.  
  320.         case 'l' : case 'L' :
  321.             i++ ;
  322.             if ( i < argc ) {
  323.             if ( argv[i][0] == '-' ||
  324.                 NULL == sscanf(argv[i],"%d",&line_limit)) {
  325.                 line_limit = DEF_LINE_LIMIT ;
  326.                 i-- ;
  327.                 break;
  328.             }}
  329.             else    line_limit = DEF_LINE_LIMIT ;
  330.             break ;
  331.  
  332.         case 'm' : case 'M' :
  333.             macro_only = TRUE ;
  334.             underline_keep = TRUE ;
  335.             com_keep = TRUE ;
  336.             break ;
  337.         
  338.         case 'i' : case 'I' :
  339.             i++ ;
  340.             if ( i < argc && *in_buff != '#' ) {
  341.                 sprintf(in_buff,
  342.                     "#include \"%s\"", argv[i] ) ;
  343.                 break ;
  344.             }
  345.             else goto ERROR ;
  346.         
  347.         case 'd' : case 'D' :
  348.             i++ ;
  349.             if ( i < argc ) {
  350.                 sprintf(out_buff, ":%s 1;", argv[i] ) ;
  351.                 define_macro( out_buff ) ;
  352.                 break ;
  353.             }
  354.         
  355. ERROR:
  356.     
  357. default:fprintf( stderr, "\nUnrecognized switch: %s\n", argv[i]);
  358.     fprintf( stderr,
  359.     "\nAllowed switches:\n\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
  360.     " -c        keep comments",
  361.     " -u        keep underline characters",
  362.     " -m        expand macros only",
  363.     " -i <file>    include <file> before processing (1 only)",
  364.     " -d <name>    define <name> as a macro ( :name 1; )",
  365.     " -r n        unroll vector loops to depth n",
  366.     " -l n        unroll loops with n or fewer lines only",
  367.     "All items must be separated by blanks"
  368.     ) ;
  369.     abort( "\n" ) ;
  370.     }
  371.     }
  372. }
  373.  
  374. /* process the file include statement if present */
  375. preproc( rec_type(0) ) ;
  376. }
  377.  
  378.  
  379.  
  380.  
  381. /* Function PREPROCESS.C
  382.  *
  383.  * The guts of the preprocessor PREP.  Variable tipe
  384.  * contains the type of record code:
  385.  *
  386.  *  BEGIN statement
  387.  *  AGAIN statement
  388.  *  WHILE statement
  389.  *  UNTIL statement
  390.  *  CONTINUE statement
  391.  *  LEAVE statement
  392.  *
  393.  *  CASE statement
  394.  *  OF statement
  395.  *  DEFAULT statement
  396.  *  CONTINUE_CASE statement
  397.  *  END_CASE statement
  398.  *  DO_LIMITS statement
  399.  *  UNROLL statement
  400.  *
  401.  *  DO statement
  402.  *  LEAVE_DO statement
  403.  *  CONTINUE_DO statement
  404.  *  END_DO statement
  405.  *
  406.  *  [  (start of clustered vector arithmetic)
  407.  *  ]  (  end  "     "        "       "     )
  408.  *  #  vectored arithmetic statement
  409.  *  normal (normal fortran statement)
  410.  *
  411.  *  INCLUDE files
  412.  *  conditional compilation:
  413.  *     #ifdef, #ifndef, #else, #endif
  414.  *
  415.  * Returns 1 if the buffer is still full, else 0.  The individual
  416.  * routines are expected to clear the buffer (in_buff) to signal
  417.  * that no more processing is required.
  418.  *
  419.  * P. R. OVE  11/9/85
  420.  */
  421.  
  422. int preproc(tipe)
  423. int tipe ;
  424. {
  425.  
  426. switch ( tipe ) {
  427.  
  428.     case unknown :        break ;
  429.     case normal :        strcpy( out_buff, in_buff ) ;
  430.                 dump( out_buff ) ;
  431.                 in_buff[0] = NULL ;
  432.                 break ;
  433.     case type_begin :    begin_proc() ; break ;
  434.     case type_again :    again_proc() ; break ;
  435.     case type_while :    while_proc() ; break ;
  436.     case type_until :    until_proc() ; break ;
  437.     case type_continue :    continue_proc() ; break ;
  438.     case type_leave :    leave_proc() ; break ;
  439.     case type_case :    case_proc() ; break ;
  440.     case type_of :        of_proc() ; break ;
  441.     case type_default :    default_proc() ; break ;
  442.     case type_continue_case:continue_case_proc() ; break ;
  443.     case type_end_case :    end_case_proc() ; break ;
  444.     case type_do_limits :    do_limits_proc() ; break ;
  445.     case type_unroll :    unroll_proc() ; break ;
  446.     case type_do :        do_proc() ; break ;
  447.     case type_end_do :    end_do_proc() ; break ;
  448.     case type_leave_do :    leave_do_proc() ; break ;
  449.     case type_continue_do :    continue_do_proc() ; break ;
  450.     case type_osqb :    osqb_proc() ; break ;
  451.     case type_vec :     vec_proc() ; break ;
  452.     case type_csqb :    csqb_proc() ; break ;
  453.     case type_include :    include_proc() ; break ;
  454.     case type_ifdef :    ifdef_proc() ; break ;
  455.     case type_ifndef :    ifndef_proc() ; break ;
  456.     case type_else :    else_proc() ; break ;
  457.     case type_endif :    endif_proc() ; break ;
  458.                       
  459. }
  460.  
  461. return( line_end( in_buff ) != NULL ) ;
  462. }
  463.  
  464.  
  465.  
  466.  
  467. /* PUSH
  468.  *
  469.  * Push a string onto the MEM_STORE.  Space is allocated for it and
  470.  * a pointer kept in the array mem_store (array of pointers).  The
  471.  * index to mem_store at which the current string is stored is returned.
  472.  * If the input string is a NULL pointer the last entry is removed.
  473.  * Global variable mem_count keeps track of the total number of pointers
  474.  * in use.
  475.  */
  476.  
  477. int push( string )
  478. char    *string ;
  479. {
  480. int    i ;
  481.  
  482. if ( string != NULL ) {
  483.     if ( mem_count >= STORE_SIZE - 1 ) {
  484.         sprintf( errline, "PUSH out of memory pointers: %s", in_buff ) ;
  485.         abort( errline ) ;
  486.     }
  487.     GET_MEM( mem_store[ mem_count ], strlen( string ) ) ;
  488.     strcpy( mem_store[ mem_count ], string ) ;
  489.     mem_count++ ;
  490.     return( mem_count - 1 ) ;
  491. }
  492.  
  493. if ( mem_count > 0 ) {
  494.     mem_count-- ;
  495.     free( mem_store[ mem_count ] ) ;
  496.     return( mem_count - 1 ) ;
  497. }
  498.  
  499. /* already empty if it gets here */
  500. return( -1 ) ;
  501. }
  502.  
  503.  
  504.  
  505. /* Function REC_TYPE.C
  506.  *
  507.  * Determine the type of a record.
  508.  *
  509.  * P. R. OVE  11/9/85
  510.  */
  511.  
  512. char    *strchrq() ;
  513.  
  514. int    rec_type( group )
  515. int    group ;
  516. {                  
  517. char    combuff[16], *string ;
  518. int    i ;
  519.  
  520. if (in_buff[0] == NULL) return((int)unknown) ;
  521. string = in_buff ;
  522.  
  523. /* go to first nonblank character, save a pointer to it */
  524. while ( *string != NULL ) {
  525.     if ( *string != TAB && *string != BLANK ) {    
  526.         first_nonblank = string ;
  527.         break ;
  528.     }
  529.     string++ ;
  530. }
  531.  
  532. /* copy the initial characters into combuff */
  533. for ( i = 0; (i < 15) && (*string != NULL); i++ ) {
  534.     combuff[i] = string[i] ;
  535. }
  536. combuff[15] = NULL ;
  537.  
  538. strupr( combuff ) ;  /* convert to upper case */
  539.  
  540.  
  541.      
  542. /* check for commands by group */
  543. switch ( group ) {
  544.  
  545.  
  546. /* group 0 commands: file includes & conditional compilation */
  547. case 0 : {
  548.     if ( MATCH( "#INCLUDE" ) ) return((int)type_include) ;
  549.     if ( MATCH( "#IFDEF" ) )   return((int)type_ifdef) ;
  550.     if ( MATCH( "#IFNDEF" ) )  return((int)type_ifndef) ;
  551.     if ( MATCH( "#IF" ) )      return((int)type_ifdef) ;
  552.     if ( MATCH( "#ELSE" ) )    return((int)type_else) ;
  553.     if ( MATCH( "#ENDIF" ) )   return((int)type_endif) ;
  554.                            return((int)unknown) ;
  555. }
  556.  
  557.  
  558. /* group 1 commands: case's OF and DEFAULT commands are done first so
  559.    that it is legal to have:  of ( 'a' ) leave_do, for instance.
  560. */
  561. case 1 : {
  562.     if ( MATCH( "OF" ) )        return((int)type_of) ;
  563.     if ( MATCH( "DEFAULT" ) )   return((int)type_default) ;
  564.                         return((int)unknown) ;
  565. }
  566.  
  567.  
  568. /* group 2 commands: flow control extensions and parameter changes */
  569. case 2 : {
  570.     if ( MATCH( "DO_LIMITS" ) ) return((int)type_do_limits) ;
  571.     if ( MATCH( "DO LIMITS" ) ) return((int)type_do_limits) ;
  572.  
  573.     if ( MATCH( "DO" ) )        return((int)type_do) ;
  574.     if ( MATCH( "END_DO" ) )    return((int)type_end_do) ;
  575.     if ( MATCH( "END DO" ) )    return((int)type_end_do) ;
  576.     if ( MATCH( "ENDDO" ) )     return((int)type_end_do) ;
  577.     if ( MATCH( "LEAVE_DO" ) )  return((int)type_leave_do) ;
  578.     if ( MATCH( "LEAVE DO" ) )  return((int)type_leave_do) ;
  579.     if ( MATCH( "CONTINUE_DO")) return((int)type_continue_do) ;
  580.     if ( MATCH( "CONTINUE DO")) return((int)type_continue_do) ;
  581.  
  582.     if ( MATCH( "CASE" ) )      return((int)type_case) ;
  583.     if ( MATCH( "END_CASE" ) )  return((int)type_end_case) ;
  584.     if ( MATCH( "END CASE" ) )  return((int)type_end_case) ;
  585.     if (MATCH("CONTINUE_CASE")) return((int)type_continue_case) ;
  586.     if (MATCH("CONTINUE CASE")) return((int)type_continue_case) ;
  587.  
  588.     if ( MATCH( "BEGIN" ) )     return((int)type_begin) ;
  589.     if ( MATCH( "AGAIN" ) )     return((int)type_again) ;
  590.     if ( MATCH( "WHILE" ) )     return((int)type_while) ;
  591.     if ( MATCH( "UNTIL" ) )     return((int)type_until) ;
  592.     if ( MATCH( "LEAVE" ) )     return((int)type_leave) ;
  593.     if ( MATCH( "CONTINUE" ) )  return((int)type_continue) ;
  594.  
  595.     if ( MATCH( "UNROLL" ) )    return((int)type_unroll) ;
  596.                     return((int)unknown) ;
  597. }
  598.  
  599.  
  600. /* group 3 commands: vector processing */
  601. case 3: {
  602.     if ( MATCH( "[" )    )             return((int)type_osqb) ;
  603.     if ( strchrq( string, ']' ) != NULL ) return((int)type_csqb) ;
  604.     if ( strchrq( string, '#' ) != NULL ) return((int)type_vec) ;
  605.                           return((int)normal) ;
  606. }
  607. } /* end switch case */
  608.  
  609.  
  610. /* control should never get here */
  611. sprintf( errline, "REC_TYPE: invalid group %d", group ) ;
  612. abort( errline ) ;
  613. return((int)unknown) ;    /* here to avoid compiler warning (Gould) */
  614. }
  615.  
  616.  
  617.  
  618. /* Comment and blank line filtering.
  619.  *
  620.  *    This routine also trims off characters after a ";", so that
  621.  * this symbol is can be used for comments on the same line.  If
  622.  * the first character on the line is ":" this is not done, since
  623.  * removing the trailing semicolon would cause a macro def error.
  624.  * The macro definition routine will eliminate anything after the
  625.  * ";" anyway.  Blank lines are also killed off here.  Returns a
  626.  * 1 if the line was entirely a comment and processed, else 0.
  627.  */        
  628. int comment_filter()
  629. {
  630. char    *start, *semi ;
  631.  
  632. start = line_end( in_buff ) ;
  633.  
  634. /* handle lines with comment character in 1st column, and blank lines */
  635. if ( (*in_buff == 'c') || (*in_buff == 'C') ||
  636.      (*in_buff == ';') || (start == NULL)    ) {
  637.         if ( com_keep ) {
  638.         if ( NOT macro_only ) in_buff[72] = NULL ;
  639.         if ( *in_buff == ';' ) *in_buff = 'c' ;
  640.         put_string( in_buff ) ;
  641.     }
  642.     return(1) ;
  643. }
  644.  
  645. /* trim off text after ; if not a macro def */
  646. if ( NOT macro_only && *start != ':' ) {
  647.     if ( NULL != ( semi = strchrq( in_buff, ';' ) ) ) *semi = NULL ;
  648. }
  649. return(0) ;
  650. }
  651.  
  652.  
  653.  
  654. /* Look for unquoted character in string, where ' is the fortran quote char.
  655.  * Returns a pointer to the character, or a NULL pointer if not present.
  656.  */
  657. char    *strchrq( string, c )
  658. char    *string, c ;
  659. {
  660. int    i, quote=1 ;
  661.  
  662. for ( i = 0; string[i] != NULL; i++ ) {
  663.     if ( string[i] == '\'' ) {
  664.         quote = -quote ;
  665.         continue ;
  666.     }
  667.     if ( string[i] == c && quote == 1 ) return( &string[i] ) ;
  668. }
  669.  
  670. return( NULL ) ;    /* not found */
  671. }
  672.  
  673.  
  674.  
  675.  
  676.  
  677. /* STRMATCH:  find the first occurrence of string2 in string1, return pointer
  678.  * to the first character of the match.  Returns NULL pointer if no match.
  679.  * This routine is fairly slow and should not be used where speed is
  680.  * critical.
  681.  */
  682. #define NULL    0
  683.  
  684. char    *strmatch( string1, string2 )
  685. char    *string1, *string2 ;
  686. {
  687. char    *pntr1, *pntr2 ;
  688.  
  689.      for ( pntr1 = string1, pntr2 = string2 ; *pntr1 != NULL; pntr1++ ) {
  690.         if ( *pntr1 == *pntr2 ) {
  691.             pntr2++ ;
  692.             if ( *pntr2 == NULL ) return( pntr1 - strlen(string2) + 1 ) ;
  693.         }
  694.         else pntr2 = string2 ;
  695.     }
  696.  
  697.     /* failure if control reaches this point */
  698.     return( NULL ) ;
  699. }
  700.  
  701.  
  702.  
  703.  
  704. /* function STRTOKP
  705.  
  706.    Like Strtok, except that the original string is preserved (strtok
  707.    puts null in there to terminate the substrings).  This routine
  708.    uses mallocs to allow storage for the token.  The memory is
  709.    reallocated for each new string.  Use just like strtok:
  710.    
  711.    Successively returns the tokens in string1, using the delimeters
  712.    defined by string2.  If string1 is NULL (a NULL pointer) the 
  713.    routine returns the next token in the string from the previous call.
  714.    Otherwise the first token is returned.  A NULL pointer is returned
  715.    on failure (no more tokens in the current string).
  716. */
  717.  
  718. char *strtokp( string1, string2 )
  719. char    *string1, *string2 ;
  720. {
  721. static char    *spntr, *tpntr, *token ;
  722. static int    called = NULL ;        /* called=NULL ==> initialize */
  723. int    i ;
  724.  
  725. /* initialize on first call */
  726.     if ( called == NULL ) {
  727.         called = 1 ;
  728.         GET_MEM( token, strlen(string1) ) ;
  729.     }
  730.  
  731. /* if string1 is not NULL reset the routine */
  732.     if ( string1 != NULL ) {
  733.         spntr = string1 ;
  734.         if ( NULL == ( token = realloc( token, strlen(string1)+1 )))
  735.             abort("STRTOKP: reallocation error") ;
  736.     }
  737.     if ( *spntr == NULL ) return( NULL ) ;    /* end of original string */
  738.  
  739. /* skip    initial delimeter characters */
  740.     for (; NULL != strchr( string2, *spntr ); spntr++ ) ;
  741.  
  742. /* copy characters to token until the next delimeter */
  743.     tpntr = &token[0] ;
  744.     for (; *spntr != NULL; spntr++ ) {
  745.         if ( NULL != strchr( string2, *spntr ) ) break ;
  746.         *tpntr = *spntr ;
  747.         tpntr++ ;
  748.     }
  749.     *tpntr = NULL ;
  750.  
  751. /* return result to caller */
  752.     if ( token[0] == NULL ) return( NULL ) ;
  753.     return( &token[0] ) ;
  754. }
  755.  
  756.  
  757.  
  758.  
  759. /* strupr: convert a string to upper case.
  760.  */
  761.  
  762. char    *strupr( string )
  763. char    *string ;
  764. {
  765. int    i ;
  766.  
  767.     for ( i=0; i<strlen( string ); i++ )
  768.         if ( string[i] > 96 && string[i] < 123 ) string[i] -= 32 ;
  769.  
  770.     return( string ) ;
  771. }
  772.  
  773.  
  774.  
  775.  
  776. /* Tokenize
  777.  *
  778.  * Break out arguments from a string.  Pntr is the argument string
  779.  * and tokens is an array of pointers which will be assigned memory and have
  780.  * the arguments returned.  The function returns the number of arguments
  781.  * found.  Pairwise characters are monitored to ensure that expressions
  782.  * are sexually balanced.  Unused parm pointers are returned NULL.
  783.  * MAX_TOKENS determines the dimension of the array of pointers.
  784.  * Commas are the only delimiters allowed to distinquish tokens.
  785.  */
  786.  
  787. int    tokenize( pntr, tokens )
  788. char    *pntr, *tokens[] ;
  789. {
  790. int    square = 0, curl = 0, parens = 0, apost = 1, quote = 1 ;
  791. int    i, j, quit ;
  792. char    *text, *txt ;
  793.  
  794. /* clear the pointers and make a copy of the string */
  795. for ( i=0; i<MAX_TOKENS; i++ ) tokens[i] = NULL ;
  796. GET_MEM( text, strlen(pntr) ) ;
  797. strcpy( text, pntr ) ;
  798.  
  799. for ( i=0, j=0, quit=FALSE, txt=text; quit==FALSE; j++ ) {
  800.  
  801.     switch( text[j] ) {
  802.  
  803.     case '['  :    square += 1 ;    break ;
  804.     case ']'  :    square -= 1 ;    break ;
  805.     case '{'  :    curl   += 1 ;    break ;
  806.     case '}'  :    curl   -= 1 ;    break ;
  807.     case '('  :    parens += 1 ;    break ;
  808.     case ')'  :    parens -= 1 ;    break ;
  809.     case '\'' :    apost = -apost;    break ;
  810.     case '\"' :    quote = -quote;    break ;
  811.     case NULL :    
  812.             GET_MEM( tokens[i], strlen(txt) ) ;
  813.             strcpy( tokens[i], txt ) ;
  814.             quit = TRUE ;
  815.             break ;
  816.     case ','  :    if (!square && !curl && !parens &&(apost==1)&&(quote==1)){
  817.                 text[j] = NULL ;
  818.                 GET_MEM( tokens[i], strlen(txt) ) ;
  819.                 strcpy( tokens[i], txt ) ;
  820.                 i += 1 ;
  821.                 txt = &text[j+1] ;
  822.             }
  823.     }
  824. }
  825.  
  826. free( text ) ;
  827. return( i+1 ) ;
  828. }
  829.